#pragma once
// 对普通socket 的模块
#include "Connection.hpp"

class Channel : public Connection
{
public:
    Channel(int sockfd, const InetAddr &addr)
    {
        // 初始化sockfd addr 关心的事件
        SetAdder(addr);
        SetSockfd(sockfd);
        SetEvents(EPOLLIN | EPOLLET);
    }
    void Recver() override
    {
        //接受消息的时候更新时间
        Update();
        // 将数据读取到输入缓冲区inbuffer 中
        // 因为为ET模式，所以此处需要循环读取
        while (true)
        {
            char buffer[1024];
            int n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            // 判断返回值，由于文件描述符为非阻塞，所以当返回值为-1的时候需要对其错误码进行判断
            if (n > 0)
            {
                // 读取成功
                buffer[n] = 0;
                _inbuffer += buffer; // 追加到inbuffer 后面
            }
            else if (n == 0)
            {
                // 对端关闭
                LOG(LogLevel::DEBUG) << "对端关闭， me too";
                // 统一异常处理
                Excepter();
                return;
            }
            else
            {
                if (errno == EAGAIN)
                {
                    // 表示数据已经读完了
                    break;
                }
                else if (errno == EINTR)
                {
                    // 信号中断
                    continue;
                }
                else
                {
                    // 真正的读错误
                    LOG(LogLevel::ERROR) << "recv error , client is :" << _peer.ToString();
                    Excepter(); // 统一异常处理
                    return;
                }
            }
        }

        // 循环结束代表将数据均读完了，那么就要将读取到的数据交给上层处理，协议--> Protocol Parser Calculator
        // 需要调用Parser中的Parse方法，对数据进行解包、反序列化、处理数据、序列化、打包，返回应答 --> Connection 中放回调函数 --> Parser 中传处理任务的模块
        _outbuffer = _cb(_inbuffer);
        std::cout << "_outbuffer: " << _outbuffer;

        // 方法一：直接将数据发回
        // if (!_outbuffer.empty())
        //     Sender();

        //方法二：使能写关心，让epoll 自动去调用Sender函数
        if(!_outbuffer.empty()) 
            Owner()->EnableReadWrite(_sockfd , true, true);
    }
    // 在多路转接中，写默认是就绪的，当有数据的时候就一只写，直到对端的接受缓冲区满了，或者数据发送完了；当对端接受缓冲区满了，我们此时send 的返回值为-1
    // 错误码为 EAGAIN ；并且每次成功发送数据，就将数据从outbuffer 中移除
    void Sender() override
    {
        Update();//更新时间

        // 由于是ET模式，需要循环发送
        while (true)
        {
            int n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
            if (n > 0)
            {
                // 成功发送数据
                _outbuffer.erase(0, n);
                // 判断数据是否发送完毕
                if (_outbuffer.empty())
                    break;
            }
            else if (n == 0)
            {
                // 对端关闭
                LOG(LogLevel::INFO) << "对端关闭， Me too , client :" << _peer.ToString();
                Excepter(); // 统一异常处理
                break;
            }
            else
            {
                // 判断错误码
                if (errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    LOG(LogLevel::INFO) << "写错误";
                    Excepter(); // 统一异常处理
                    break;
                }
            }
        }

        // 写完毕，走到此处要么发完了，要么是对端接受缓冲区满了
        //判断——outbuffer 中是否有数据便可以区分
        if(_outbuffer.empty())
        {
            //写完了;不管是否有将这个文件描述符的写事件进行关心，均需要关闭 --> 在Reactor 中设置方法
            Owner()->EnableReadWrite(_sockfd , true , false);
        }
        else
        {
            // 对端接受缓冲区满了，将写事件添加进epoll 中
            Owner()-> EnableReadWrite(_sockfd , true , true);
        }

    }
    void Excepter() override
    {
        //异常处理，出了异常就将这个fd 从_connetcions 中移除，即调用Reactor 中的方法 DelConnection
        Owner()->DelConection(_sockfd);
    }

private:
};